/*
 *  Main class of GAPI for .NET
 *  we shall use mainly methods that expose from this class
 */

using Cik.Gapi4Net.Domain.Input;

namespace Cik.Gapi4Net
{
    #region namespace

    using System;
    using System.Diagnostics.Contracts;
    using Core.AcsynRequest;
    using Core.Exceptions;
    using Domain.Input.UrlBuilder;
    using Domain.Input.Validator;
    using Domain.Output.BlogSearch;
    using Domain.Output.BookSearch;
    using Domain.Output.ImageSearch;
    using Domain.Output.LocalSearch;
    using Domain.Output.NewsSearch;
    using Domain.Output.PatentSearch;
    using Domain.Output.TranslateSearch.DetectLanguage;
    using Domain.Output.TranslateSearch.TranslateLanguage;
    using Domain.Output.VideoSearch;
    using Domain.Output.WebSearch;
    using Entlib.Container;
    using Entlib.Logging;
    using FluentValidation;
    using Microsoft.Practices.ServiceLocation;
    using Microsoft.Practices.Unity;
    using Service.Contracts;
    using Service.Impls;
    using Gapi4NetDomain = Domain.Input;

    #endregion namespace

    public class GApi4Net : IGApi4Net
    {
        #region private variables

        private readonly IUnityContainer _container;

        #endregion private variables

        #region ctors

        public GApi4Net()
        {
            _container = new UnityContainer();
            RegisterService();
            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(_container));
            SetAllServiceForSetters();
        }

        #endregion ctors

        #region SearchService

        public IBlogSearchService BlogService { get; internal set; }

        public IBookSearchService BookService { get; internal set; }

        public IImageSearchService ImageService { get; internal set; }

        public ILocalSearchService LocalService { get; internal set; }

        public INewsSearchService NewsService { get; internal set; }

        public IPatentSearchService PatentService { get; internal set; }

        public ITranslateService TranslateService { get; internal set; }

        public IWebSearchService WebService { get; internal set; }

        public IVideoSearchService VideoService { get; internal set; }

        public BlogSearchResult BlogSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(BlogService != null, "BlogService is null");

            try
            {
                return BlogService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public BlogSearchResult BlogSearch(Func<Gapi4NetDomain.Blog> func)
        {
            Contract.Assert(BlogService != null, "BlogService is null");

            try
            {
                return BlogService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public BookSearchResult BookSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(BookService != null, "BookService is null");

            try
            {
                return BookService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public BookSearchResult BookSearch(Func<Book> func)
        {
            Contract.Assert(BookService != null, "BookService is null");

            try
            {
                return BookService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public ImageSearchResult ImageSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(ImageService != null, "ImageService is null");

            try
            {
                return ImageService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public ImageSearchResult ImageSearch(Func<Domain.Input.Image> func)
        {
            Contract.Assert(ImageService != null, "ImageService is null");

            try
            {
                return ImageService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public LocalSearchResult LocalSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(LocalService != null, "LocalService is null");

            try
            {
                return LocalService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public LocalSearchResult LocalSearch(Func<Local> func)
        {
            Contract.Assert(LocalService != null, "LocalService is null");

            try
            {
                return LocalService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public NewsSearchResult NewsSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(NewsService != null, "NewsService is null");

            try
            {
                return NewsService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public NewsSearchResult NewsSearch(Func<Gapi4NetDomain.News> func)
        {
            Contract.Assert(NewsService != null, "NewsService is null");

            try
            {
                return NewsService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public PatentSearchResult PatentSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(PatentService != null, "PatentService is null");

            try
            {
                return PatentService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public PatentSearchResult PatentSearch(Func<Patent> func)
        {
            Contract.Assert(PatentService != null, "PatentService is null");

            try
            {
                return PatentService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public TranslateResult TranslateSearch(string version = "1.0", string query = "Hello world", string languagePair = "en|it")
        {
            Contract.Assert(TranslateService != null, "TranslateService is null");

            try
            {
                return TranslateService.Translate(version, query, languagePair);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public DetectResult DetectSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(TranslateService != null, "TranslateService is null");

            try
            {
                return TranslateService.DetectLanguage(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public VideoSearchResult VideoSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(VideoService != null, "VideoService is null");

            try
            {
                return VideoService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public VideoSearchResult VideoSearch(Func<Video> func)
        {
            Contract.Assert(VideoService != null, "VideoService is null");

            try
            {
                return VideoService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public WebSearchResult WebSearch(string version = "1.0", string query = "Google")
        {
            Contract.Assert(WebService != null, "WebService is null");

            try
            {
                return WebService.Search(version, query);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        public WebSearchResult WebSearch(Func<Web> func)
        {
            Contract.Assert(WebService != null, "WebService is null");

            try
            {
                return WebService.Search(func);
            }
            catch (GApi4NetException ex)
            {
                throw;
            }
        }

        #endregion SearchService

        #region private methods

        private void SetAllServiceForSetters()
        {
            BlogService = IoC.GetInstance<IBlogSearchService>();
            BookService = IoC.GetInstance<IBookSearchService>();
            ImageService = IoC.GetInstance<IImageSearchService>();
            LocalService = IoC.GetInstance<ILocalSearchService>();
            NewsService = IoC.GetInstance<INewsSearchService>();
            PatentService = IoC.GetInstance<IPatentSearchService>();
            TranslateService = IoC.GetInstance<ITranslateService>();
            VideoService = IoC.GetInstance<IVideoSearchService>();
            WebService = IoC.GetInstance<IWebSearchService>();
        }

        private void RegisterService()
        {
            _container.RegisterType(typeof(ILoggerFactory), typeof(LoggerFactory));
            _container.RegisterType(typeof(IDownloader), typeof(Downloader));

            _container.RegisterType(typeof(IUrlBuilder<Blog>), typeof(BlogUrlBuilder));
            _container.RegisterType(typeof(IValidator<Blog>), typeof(BlogValidator));

            _container.RegisterType(typeof(IUrlBuilder<Book>), typeof(BookUrlBuilder));
            _container.RegisterType(typeof(IValidator<Book>), typeof(BookValidator));

            _container.RegisterType(typeof(IUrlBuilder<Gapi4NetDomain.Image>), typeof(ImageUrlBuilder));
            _container.RegisterType(typeof(IValidator<Gapi4NetDomain.Image>), typeof(ImageValidator));

            _container.RegisterType(typeof(IUrlBuilder<Local>), typeof(LocalUrlBuilder));
            _container.RegisterType(typeof(IValidator<Local>), typeof(LocalValidator));

            _container.RegisterType(typeof(IUrlBuilder<News>), typeof(NewsUrlBuilder));
            _container.RegisterType(typeof(IValidator<News>), typeof(NewsValidator));

            _container.RegisterType(typeof(IUrlBuilder<Patent>), typeof(PatentUrlBuilder));
            _container.RegisterType(typeof(IValidator<Patent>), typeof(PatentValidator));

            _container.RegisterType(typeof(IUrlBuilder<Translate>), typeof(TranslateUrlBuilder));
            _container.RegisterType(typeof(IValidator<Translate>), typeof(TranslateValidator));

            _container.RegisterType(typeof(IUrlBuilder<Video>), typeof(VideoUrlBuilder));
            _container.RegisterType(typeof(IValidator<Video>), typeof(VideoValidator));

            _container.RegisterType(typeof(IUrlBuilder<Web>), typeof(WebUrlBuilder));
            _container.RegisterType(typeof(IValidator<Web>), typeof(WebValidator));

            _container.RegisterType(typeof(IBlogSearchService), typeof(BlogSearchService));
            _container.RegisterType(typeof(IBookSearchService), typeof(BookSearchService));
            _container.RegisterType(typeof(IImageSearchService), typeof(ImageSearchService));
            _container.RegisterType(typeof(ILocalSearchService), typeof(LocalSearchService));
            _container.RegisterType(typeof(INewsSearchService), typeof(NewsSearchService));
            _container.RegisterType(typeof(IPatentSearchService), typeof(PatentSearchService));
            _container.RegisterType(typeof(ITranslateService), typeof(TranslateService));
            _container.RegisterType(typeof(IVideoSearchService), typeof(VideoSearchService));
            _container.RegisterType(typeof(IWebSearchService), typeof(WebSearchService));
        }

        #endregion private methods
    }
}